﻿/*------------------------------------------------------------------------

RENDER_WIN32_D3D9.HPP v1.1.5

Copyright 楊志賢 CxxlMan, 2012 - 2014
All Rights Reserved


------------------------------------------------------------------------*/

#if !defined(__RENDER_WIN32_D3D9_HPP_Cxxl3D)
#define __RENDER_WIN32_D3D9_HPP_Cxxl3D

#include <Window\Window_Win32\WINDOW_WIN32.HPP>
#include <Render\RENDER.HPP>
#include <d3d9.h>

// 元件介面的識別碼
#define IRender_Win32_D3d9_ClassID L"6575FB9E-D824-4bca-A1B2-97A5A7B2BA84"


namespace Cxxl3D
{


// 作為 IRender_Win32_D3d9::Init() 的參數
typedef bool (cxxlFASTCALL *InitD3d9Func)(LPDIRECT3DDEVICE9 pDEVICE9);

class IDatagramDisposal_D3d9;

class IRenderDatagramDisposalCenterD3d:virtual public CxxlMan::cxxlObject
{
public:
  // Constructor
  IRenderDatagramDisposalCenterD3d()
    :cxxlObject(CxxlMan::Spirit_Easy)
  {}
  // Destructor
  virtual ~IRenderDatagramDisposalCenterD3d(){}

  // 執行渲染，若 IRenderDatagram_Arg 對應的 IDatagramDisposal 不存在回覆 false
  virtual bool cxxlFASTCALL Exec(const CxxlMan::Smart_Ptr<IRenderDatagram> &IRenderDatagram_Arg, LPDIRECT3DDEVICE9 pDEVICE9) = 0;

  // 取得 ID 指定的 DD_D3d9
  virtual CxxlMan::Smart_Ptr<IDatagramDisposal_D3d9> cxxlFASTCALL GetIDatagramDisposal_D3d9(CxxlMan::UNICODE_String ID) = 0;

};

inline bool cxxlFASTCALL DefaultInitD3d9Func(LPDIRECT3DDEVICE9 pDEVICE9)
{
  return true;
}

class IDatagramDisposal_D3d9:public IDatagramDisposal
{
public:
  // Constructor
  IDatagramDisposal_D3d9()
    :cxxlObject(CxxlMan::Spirit_Easy)
  {
  }

  // Destructor
  virtual ~IDatagramDisposal_D3d9()
  {
  }


  // 若有子 IRenderDatagram 對應的 IDatagramDisposal 不存在回覆 false
  virtual bool cxxlFASTCALL Exec(const CxxlMan::Smart_Ptr<IRenderDatagramDisposalCenterD3d> &IRenderDatagramDisposalCenterD3d_Arg,
    const CxxlMan::Smart_Ptr<IRenderDatagram> &IRenderDatagram_Arg, LPDIRECT3DDEVICE9 pDEVICE9) = 0;

};


class IRender_Win32_D3d9:public IRender, public IWindowWin32_Observer
{
  virtual void cxxlFASTCALL SysInit(const CxxlMan::Smart_Ptr<IWindow_Win32> &IWindow_Win32_Arg) = 0;

protected:

  virtual bool cxxlFASTCALL Ref(CxxlMan::Filter *F) = 0
  {
    if(F != NULL && IRender::Ref(F))
      return true;
    else
      return false;
  }

public:
  // Constructor
  IRender_Win32_D3d9()
    :cxxlObject(CxxlMan::Spirit_Easy),
    cxxlPreserve2(IRender_Win32_D3d9_ClassID)
  {

  }
  // Destructor
  virtual ~IRender_Win32_D3d9(){}

  // 保存永續儲存資料
  virtual bool cxxlFASTCALL Save(const CxxlMan::Smart_Ptr<CxxlMan::IcxxlStorage> &IcxxlStorage_Arg, const CxxlMan::UNICODE_String &BackupName) = 0;

  // 取回永續儲存資料，並立即執行，若有錯誤原資料不變
  virtual bool cxxlFASTCALL Load(const CxxlMan::Smart_Ptr<CxxlMan::IcxxlStorage> &IcxxlStorage_Arg, const CxxlMan::UNICODE_String &BackupName) = 0;

  // 會呼叫 IWindow_Win32::Reset()
  virtual bool cxxlFASTCALL Reset() = 0;

  // 初始一些 D3D 內定設定
  virtual bool cxxlFASTCALL Init(InitD3d9Func pInitD3d9Func_Arg = DefaultInitD3d9Func) = 0;

  // 以目前指定的 OpenGL 設定再執行一次，成功回覆 true，失敗表示目前指定的視窗模式不適用
  //virtual bool cxxlFASTCALL ReAct() const = 0;


public:

  // 取得 IRender_Win32_D3d9 物件，失敗傳回 NULL
  static CxxlMan::Smart_Ptr<IRender_Win32_D3d9> cxxlFASTCALL Create(const CxxlMan::Smart_Ptr<IWindow_Win32> &IWindow_Win32_Arg = NULL)
  {
    CxxlMan::Smart_Ptr<IWindow_Win32> IWindow_Win32_Ptr = IWindow_Win32_Arg;
    if(IWindow_Win32_Arg.isNULL())
    {
      IWindow_Win32_Ptr = IWindow_Win32::Create();
      if(IWindow_Win32_Ptr.isNULL())
        return NULL;
      IWindow_Win32_Ptr->Reset();
    }

    CxxlMan::Smart_Ptr<IRender_Win32_D3d9> r = 
      CxxlMan::Preserve2_Cast<IRender_Win32_D3d9>( CxxlMan::cxxlCM_GetElement(IRender_Win32_D3d9_ClassID, CXXL3DDEFAULTGROUP) );

    if(r.isNULL() != true)
    {
      r->SysInit(IWindow_Win32_Ptr);
      IWindow_Win32_Ptr->Attach((IRender_Win32_D3d9*)r);
    }

    return r;
  }

  // 從永存資料產生 IRender_Win32_D3d9 物件，並立即依保存的永存資料建立視窗
  // 失敗傳回 NULL
  static CxxlMan::Smart_Ptr<IRender_Win32_D3d9> cxxlFASTCALL Create(const CxxlMan::UNICODE_String &BackupName, const CxxlMan::Smart_Ptr<CxxlMan::IcxxlStorage> &IcxxlStorage_Arg)
  {
    CxxlMan::Smart_Ptr<cxxlPreserve2> cxxlPreserve2_Ptr(NULL);
    CxxlMan::REGENERARETURN_TYPE rt = cxxlCM_Regenera(cxxlPreserve2_Ptr, BackupName, IcxxlStorage_Arg, true);
    if(rt == CxxlMan::Regenera_Success)
    {
      CxxlMan::Smart_Ptr<IRender_Win32_D3d9> IRender_Win32_D3d9_Ptr = CxxlMan::Smart_Cast<IRender_Win32_D3d9>(cxxlPreserve2_Ptr);
      if(IRender_Win32_D3d9_Ptr.isNULL() == false && IRender_Win32_D3d9_Ptr->Reset())
        return IRender_Win32_D3d9_Ptr;
    }
    return NULL;
  }

  friend class CxxlMan::IcxxlStorage;
  friend class CxxlMan::Smart_Ptr<IRender_Win32_D3d9>;
};


// 初始化，這裡只做元件註冊
inline void Render_Win32_D3d9_Init()
{
  CxxlMan::cxxlCM_ElementReg(IRender_Win32_D3d9_ClassID, CXXL3DDEFAULTGROUP, L"Render_Win32_D3d9.dll");
}


}   /* namespace Cxxl3D */
#endif

